﻿#include "QMyGraphicsView.h"
#include <QWheelEvent>
#include <QGraphicsItem>
#include <QKeyEvent>
#include <QDebug>
#include <QMenu>
#include <QApplication>

QMyGraphicsView::QMyGraphicsView(QWidget *parent)
    : QGraphicsView(parent),
      m_translateSpeed(1.0),
      m_zoomDelta(0.1),

      is_mousePress(false),
      is_mouseMove(false),
      m_scale(1.0),
      mouseDelta(0,0),
      sum_translate(0,0),
      sum_rotation(0.0)
{
    // 去掉滚动条
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    setRenderHint(QPainter::Antialiasing);
    setSceneRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX);
}

// 设置平移速度
void QMyGraphicsView::setTranslateSpeed(qreal speed)
{
    // 建议平移速度范围
    Q_ASSERT_X(speed >= 0.0 && speed <= 2.0,
               "QMyGraphicsView::setTranslateSpeed", "Speed should be in range [0.0, 2.0].");
    m_translateSpeed = speed;
}

// 查看当前平移速度
qreal QMyGraphicsView::translateSpeed() const   {return m_translateSpeed;}

// 设置缩放增量
void QMyGraphicsView::setZoomDelta(qreal delta)
{
    // 建议缩放增量范围
    Q_ASSERT_X(delta >= 0.0 && delta <= 1.0,
               "QMyGraphicsView::setZoomDelta", "Delta should be in range [0.0, 1.0].");
    m_zoomDelta = delta;
}

// 查看当前缩放增量
qreal QMyGraphicsView::zoomDelta() const    {return m_zoomDelta;}

// 上/下/左/右键向各个方向移动、加/减键进行缩放、空格/回车键旋转
void QMyGraphicsView::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Up:
        translate(QPointF(0, -2));  //上移
        break;
    case Qt::Key_Down:
        translate(QPointF(0, 2));   // 下移
        break;
    case Qt::Key_Left:
        translate(QPointF(-2,0));   // 左移
        break;
    case Qt::Key_Right:
        translate(QPointF(2,0));    // 右移
        break;
    case Qt::Key_Plus:              // 放大
        zoomIn();
        break;
    case Qt::Key_Minus:             // 缩小
        zoomOut();
        break;
    case Qt::Key_Space:             // 逆时针旋转
        sum_rotation+=5;
        emit transformview(sum_translate,sum_rotation,m_scale);
        break;
    default:
        QGraphicsView::keyPressEvent(event);
    }
}

// 接收鼠标指针移动动作
void QMyGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    //当鼠标中键被按下时记录坐标并实时移动
    if ((event->buttons() & Qt::MidButton) && is_mousePress)
    {
        mouseDelta = mapToScene(event->pos()) - mapToScene(m_lastMousePos);
        translate(mouseDelta);
    }
    else if (event->buttons() & Qt::LeftButton)
    {
        is_mouseMove=true;
        if(rubberBand)
        {
            NewRect=QRect(origin,event->pos()).normalized();
            rubberBand->setGeometry(NewRect);
        }
    }

    //记录鼠标最后坐标
    m_lastMousePos = event->pos();

    //当鼠标指针移动时向主窗口发送显示指针位置的信号
    if (QGraphicsItem *item = itemAt(event->pos()))
    {
        //当鼠标位于图元上时
        //当鼠标左键未被按下时将鼠标设置为十字丝光标
        if (! is_mousePress) setCursor(Qt::CrossCursor);
        //将鼠标指针在视图上的位置转换为图元位置并发送该坐标
        QPointF sceneMousePos = this->mapToScene(event->pos())-sum_translate;
        QPointF itemMousePos = item->mapFromScene(sceneMousePos);
        emit updateItemPos(itemMousePos);
        mouseDelta=QPointF(0,0);
    }
    else {
        //当鼠标不在图元上时,恢复鼠标默认光标,并发送未定义坐标
        setCursor(Qt::ArrowCursor);
        QPointF p(-1,-1);
        emit updateItemPos(p);
    }

    QGraphicsView::mouseMoveEvent(event);
}

// 接收鼠标指针按压动作
void QMyGraphicsView::mousePressEvent(QMouseEvent *event)
{
    //当鼠标中键被按下时
    if (event->button() == Qt::MidButton)
    {
        QPointF point = mapToScene(event->pos());
        {
            //调试信息
            if (scene()==NULL) qDebug() <<"form line 142 in QMyGraphicsView.cpp\n当前视图中不存在可视化的场景,请向当前视图中添加场景后重试" << scene();
        }

        //当鼠标位于图元上时才能进行移动,参考"QGraphicsItem *item = itemAt(event->pos())"
        if (scene()!= NULL)
        if (scene()->itemAt(point, transform()) != NULL)
        {
            //移动时设置鼠标拖动光标,并将按压标识设置为True
            setCursor(Qt::ClosedHandCursor);
            is_mousePress = true;
            m_lastMousePos = event->pos();
        }
    }
    else if (event->button() == Qt::LeftButton)
    {
        origin=event->pos();
        if(!rubberBand)
            rubberBand = new QRubberBand(QRubberBand::Rectangle,this);
        rubberBand->setGeometry(QRect(origin,QSize()));
        rubberBand->show();
    }

    QGraphicsView::mousePressEvent(event);
}

// 接收鼠标指针按压松开动作
void QMyGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    //当鼠标左键松开时将按压标识设置为False
    if (QGraphicsItem *item = itemAt(event->pos()))
    {
        if (event->button() == Qt::MidButton)
        {
            is_mousePress = false;
            setCursor(Qt::CrossCursor);
        }
        else if (event->button() == Qt::LeftButton)
        {
            is_mousePress = false;
            if (! is_mouseMove)
            {
                QPointF sceneMousePos = this->mapToScene(event->pos());
                emit sendcrossitempos(sceneMousePos);
                emit sendcrossitemscale(m_scale);
            }
        }
    }

    if (event->button() == Qt::LeftButton && is_mouseMove)
    {
        is_mouseMove=false;
        if(rubberBand)
        {
            emit sendcrossitemselect(NewRect);
            rubberBand->hide();
        }
    }

    QGraphicsView::mouseReleaseEvent(event);
}

// 使用鼠标滚轮放大缩小
void QMyGraphicsView::wheelEvent(QWheelEvent *event)
{
    //鼠标滚轮的滚动量
    QPoint scrollAmount = event->angleDelta();
    //滚轮正值表示放大,负值表示缩小
    scrollAmount.y() > 0 ? zoomIn() : zoomOut();

}

// 放缩命令
void QMyGraphicsView::zoomIn() { zoom(1+m_zoomDelta); }
void QMyGraphicsView::zoomOut() { zoom(1-m_zoomDelta); }

// 缩放实现函数,scaleFactor:缩放的比例因子
void QMyGraphicsView::zoom(float scaleFactor)
{
    //防止缩放过大或者过小
    qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
    if (factor < 0.1 || factor > 200)
        return;

    scale(scaleFactor, scaleFactor);

    m_scale *= scaleFactor;
    emit sendcrossitemscale(m_scale);
}

// 平移实现函数
void QMyGraphicsView::translate(QPointF tran)
{
    tran *=m_translateSpeed;
    sum_translate+=tran;
    //qDebug() <<"sum_translate" <<sum_translate;
    emit transformview(tran,sum_rotation,m_scale);
}

// 重置图片位置
void QMyGraphicsView::ResetItem()
{
    sum_translate=QPointF(0,0);
    sum_rotation=0;
    m_scale=1;
    is_mousePress=false;
    mouseDelta=QPointF(0,0);
    qDebug() <<"From line 207 in QMyGraphicsView.cpp:Position has reset.";
    qDebug() <<"--------------------------------------------------------------------------------";
    resetTransform();
    emit transformview(sum_translate,sum_rotation,m_scale);
}

//右键菜单
void QMyGraphicsView::contextMenuEvent(QContextMenuEvent *event)
{
    QPoint pos = event->pos();    
    pos = this->mapToGlobal(pos);
    QMenu *menu = new QMenu(this);
    menu->addSeparator();

    QAction *zoomInAction = new QAction(this);
    zoomInAction->setText("放大");
    QIcon zoomin_icon("qrc:/ico/mousemenu_zoomin.png");
    zoomInAction->setIcon(zoomin_icon);
    connect(zoomInAction, &QAction::triggered, this, &QMyGraphicsView::zoomIn);
    menu->addAction(zoomInAction);

    QAction *zoomOutAction = new QAction(this);
    zoomOutAction->setText("缩小");
    QIcon zoomout_icon("qrc:/ico/mousemenu_zoomout.png");
    zoomOutAction->setIcon(zoomout_icon);
    connect(zoomOutAction, &QAction::triggered, this, &QMyGraphicsView::zoomOut);
    menu->addAction(zoomOutAction);

    /*
    QAction *resetAction = new QAction(this);
    resetAction->setText("还原");
    QIcon reset_icon("qrc:/ico/mousemenu_reset.png");
    resetAction->setIcon(reset_icon);
    connect(resetAction, &QAction::triggered, this, &QMyGraphicsView::ResetItem);
    menu->addAction(resetAction);
    */

    menu->exec(pos);
}

void QMyGraphicsView::updattran0(QPointF tran)
{
    translate(tran);
}
